/**
 * 绑定消息操作按钮事件
 *
 * @param {HTMLElement} messageElement - 消息元素
 *
 * @param {Object} message - 消息对象
 */
function bindMessageActionEvents(messageElement, message) {
	/**
	 * 获取复制按钮
	 */
	const copyButton = messageElement.querySelector(".copy_message_button");
	// 绑定复制功能
	copyButton?.addEventListener("click",
		() => {
			// 创建临时 textarea
			const textArea = document.createElement('textarea');
			try {
				textArea.value = message.content;

				// 设置样式防止页面跳动
				textArea.style.position = 'fixed';
				textArea.style.top = '-9999px';
				textArea.style.left = '-9999px';

				document.body.appendChild(textArea);
				textArea.select();
				textArea.setSelectionRange(0, 99999); // 移动设备兼容
				// 复制文本
				document.execCommand('copy');

				showCopySuccess(copyButton);
			}
			catch (error) {
				// 捕获异常并显示错误信息
				showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
			}
			finally {
				// 清理 DOM
				document.body.removeChild(textArea);
			}
		}
	);

	// 显示复制成功状态
	function showCopySuccess(button) {
		const originalIcon = button.innerHTML;
		button.innerHTML = '<i class="fas fa-check"></i>';
		setTimeout(() => { button.innerHTML = originalIcon; }, 2000);
	};
	/** 在消息元素中查找删除按钮 */
	const deleteButton = messageElement.querySelector(".delete_message_button");
	// 绑定删除功能
	deleteButton?.addEventListener("click",
		async () => {
			/** 在 conversationHistory 数组中查找匹配的消息索引 */
			const index = conversationHistory.findIndex(msg => msg.timestamp === message.timestamp && msg.content === message.content);
			// 若找到该消息（索引不为 -1），则从 conversationHistory 数组中移除该消息
			if (index !== -1) conversationHistory.splice(index, 1);
			// 中止当前可能正在进行的异步操作，确保在删除消息时清理相关请求
			if (abortController) abortController.abort();
			// 从DOM中删除此消息元素，更新页面显示
			messageElement.remove();
			// 显示删除成功的通知，告知用户操作结果
			showSystemMessage("消息已删除", "success");
			// 检查消息是否包含文件 URL，如果不包含则直接返回，不执行文件删除操作
			if (!message.fileUrl) return;
			// 若消息包含文件 URL，发送 DELETE 请求到服务器，删除对应的文件
			await fetch('/delete/' + message.fileUrl, { method: 'DELETE' });
			// 显示系统消息，告知用户文件已成功删除
			showSystemMessage("文件已删除", "success");
		}
	);
	/** 在消息元素中查找播放按钮 */
	const playButton = messageElement.querySelector(".play_speech_button");
	// 绑定播放事件
	playButton?.addEventListener("click",
		() => {
			/** 从消息内容中提取结论部分，用于文本转语音 */
			const content = cleanTextForTTS(extractConclusion(message.content));
			// 播放TTS
			playSpeechModel(content);
		}
	);
};

/**
 * 绑定折叠思考区按钮
 *
 * @param {HTMLButtonElement} button 折叠按钮
 */
function bindFoldingButton(button) {
	// 绑定点击事件
	button.addEventListener("click",
		() => {
			/** 在消息元素中查找 think 区块内容元素 */
			const thinkContent = button.closest(".think-block").querySelector(".think-content");
			// 切换内容
			thinkContent.classList.toggle("collapsed");
			// 切换按钮图标
			if (thinkContent.classList.contains("collapsed")) button.innerHTML = '<i class="fas fa-angle-down"></i>';
			else button.innerHTML = '<i class="fas fa-angle-up"></i>';
		}
	);
	/** 在消息元素中查找 think 区块内容元素 */
	const thinkContent = button.closest(".think-block").querySelector(".think-content");
	// 折叠think内容
	thinkContent.classList.toggle("collapsed");
};

/**
 * 创建并配置停止生成按钮，将其添加到指定消息元素的操作面板中，
 *
 * 同时绑定点击事件以支持中止当前的API请求。
 *
 * @param {HTMLElement} messageElement - 消息元素，用于查找消息操作面板并添加停止按钮
 */
function createStopButton(messageElement) {
	/** 创建停止生成按钮元素，用于在用户需要时中止API请求 */
	const stopButton = document.createElement("button");
	// 为停止按钮添加样式类，方便进行样式控制
	stopButton.className = "chat-action-button stop_generation_button";
	// 设置停止按钮的鼠标悬停提示，告知用户该按钮的功能
	stopButton.title = "停止生成";
	// 设置停止按钮的内部 HTML，显示停止图标
	stopButton.innerHTML = '<i class="fas fa-stop"></i>';
	/** 在消息元素中查找消息操作面板，该面板用于放置操作按钮 */
	const messageActionsPanel = messageElement.querySelector('.message-actions-panel');
	// 如果找到消息操作面板，则将停止按钮添加到该面板中
	if (messageActionsPanel) messageActionsPanel.appendChild(stopButton);
	// 绑定停止按钮事件，用于在用户点击时中止当前的API请求
	stopButton.addEventListener('click',
		() => {
			// 若中止控制器不存在，则不执行后续操作
			if (!abortController) return;
			// 调用中止控制器的abort方法，中止当前正在进行的API请求
			abortController.abort();
			// 禁用停止按钮，防止用户重复点击导致意外行为
			stopButton.disabled = true;
			// 更改停止按钮的图标为禁止图标，直观提示用户请求已中止
			stopButton.innerHTML = '<i class="fas fa-ban"></i>';
		}
	);
};

/**
 * 绑定代码执行按钮事件
 *
 * @param {HTMLElement} container - 包含代码块的容器元素
 */
function bindCodeExecuteButtons(container) {
	/** 为单个代码块创建并绑定执行按钮 */
	function createBinding(codeBlock) {
		/** 创建代码执行按钮 */
		const executeButton = document.createElement("button");
		// 设置按钮的类名，方便样式控制
		executeButton.className = "execute-code-button";
		// 设置按钮的内部 HTML，显示播放图标
		executeButton.innerHTML = '<i class="fas fa-play"></i>';
		// 设置按钮的鼠标悬停提示，告知用户该按钮的功能
		executeButton.title = "执行";
		/** 创建并渲染一个新的页面，将代码块内容嵌入到 iframe 中显示 */
		function createPageRender() {
			// 清空简单渲染面板的内容，准备新的渲染
			simpleRenderingPanel.innerHTML = '';
			// 显示聊天记录按钮
			chatHistoryButton.style.display = "flex";
			/** 渲染消息元素 */
			const messageElement = renderMessage(createMessageObject("user", '', false, true), simpleRenderingPanel);
			/** 创建一个 iframe 元素，用于显示代码块内容 */
			const iframe = document.createElement('iframe');
			// 设置 iframe 的样式，使其填满父元素
			iframe.style.cssText = 'width:100%; height:100%; border:0';
			// 将代码块的文本内容设置为 iframe 的文档内容
			iframe.srcdoc = codeBlock.textContent;
			// 设置 iframe 的沙箱属性，允许脚本执行
			iframe.sandbox = 'allow-modals allow-forms allow-popups allow-scripts';
			// 清空消息元素的内容
			messageElement.innerHTML = '';
			// 将 iframe 添加到消息元素中
			messageElement.appendChild(iframe);
			// 设置消息元素的高度为 100%
			messageElement.style.height = '100%';
			// 设置消息元素的最小高度
			messageElement.style.minHeight = 'calc(100vh - 500px)';
			// 设置配置面板选项
			configurePanelOption = 'simpleRenderingButton';
			// 清除所有配置面板
			eraseAllConfigurePanel();
			// 显示轻量渲染容器面板
			simpleRenderingContainerPanel.style.display = "flex";
		};
		// 为执行按钮绑定点击事件，点击时调用 createPageRender 函数
		executeButton.addEventListener("click", () => createPageRender());
		// 若代码块的定位方式不是 relative 或 absolute，则将其设置为 relative
		if (codeBlock.style.position !== "relative" && codeBlock.style.position !== "absolute") {
			codeBlock.style.position = "relative";
		};
		// 将执行按钮添加到代码块中
		codeBlock.appendChild(executeButton);
	}
	// 遍历容器内所有指定类名的代码块，并为其创建绑定
	container.querySelectorAll(".language-html.hljs.language-xml").forEach(codeBlock => createBinding(codeBlock));
};

/**
 * 绑定聊天发送
 *
 * @param {KeyboardEvent} event - 按键事件
 */
function bindChatSend(event) {
	// 判断是否正在生成
	if (getInputButtonsDisabledState()) return;
	// 仅处理 Enter 键
	if (event.key !== "Enter") return;
	// Ctrl + Enter: 允许默认换行行为
	if (event.ctrlKey) return;
	// Shift + Enter: 允许默认换行行为
	if (event.shiftKey) return;
	// 禁用回车行为
	event.preventDefault();
	// 发送消息
	sendChatMessageToBackendModel();
};

// 角色互动模式 聊天发送事件
live2dInputBox.addEventListener("keypress", bindChatSend);
// 常规聊天模式 聊天发送事件
chatInputBox.addEventListener("keypress", bindChatSend);